package cn.turboinfo.fuyang.api.provider.common.service.impl.user;

import cn.turboinfo.fuyang.api.domain.common.service.user.UserLoginService;
import cn.turboinfo.fuyang.api.domain.common.service.user.UserThirdPartyService;
import cn.turboinfo.fuyang.api.entity.common.enumeration.user.LoginCheckType;
import cn.turboinfo.fuyang.api.entity.common.enumeration.user.LoginNameType;
import cn.turboinfo.fuyang.api.entity.common.enumeration.user.ThirdPartyType;
import cn.turboinfo.fuyang.api.entity.common.exception.user.UserLoginException;
import cn.turboinfo.fuyang.api.entity.common.exception.user.UserThirdPartyException;
import cn.turboinfo.fuyang.api.entity.common.pojo.user.UserLoginCreator;
import cn.turboinfo.fuyang.api.entity.common.pojo.user.UserThirdParty;
import cn.turboinfo.fuyang.api.entity.common.pojo.user.UserThirdPartyCreator;
import cn.turboinfo.fuyang.api.entity.common.pojo.user.UserThirdPartyUpdater;
import cn.turboinfo.fuyang.api.provider.common.repository.database.user.UserThirdPartyDAO;
import cn.turboinfo.fuyang.api.provider.common.repository.database.user.UserThirdPartyPO;
import lombok.RequiredArgsConstructor;
import net.sunshow.toolkit.core.qbean.api.request.QPage;
import net.sunshow.toolkit.core.qbean.api.request.QRequest;
import net.sunshow.toolkit.core.qbean.api.response.QResponse;
import net.sunshow.toolkit.core.qbean.helper.component.request.QBeanCreatorHelper;
import net.sunshow.toolkit.core.qbean.helper.component.request.QBeanUpdaterHelper;
import net.sunshow.toolkit.core.qbean.helper.service.impl.AbstractQServiceImpl;
import org.springframework.data.domain.Page;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.Collection;
import java.util.List;
import java.util.Optional;
import java.util.function.Supplier;

@RequiredArgsConstructor
@Service
public class UserThirdPartyServiceImpl extends AbstractQServiceImpl<UserThirdParty> implements UserThirdPartyService {

    private final UserThirdPartyDAO userThirdPartyDAO;

    private final UserLoginService userLoginService;

    @Override
    public Optional<UserThirdParty> getById(Long id) {
        return userThirdPartyDAO.findById(id).map(this::convertQBean);
    }

    @Override
    public UserThirdParty getByIdEnsure(Long id) {
        return getById(id).orElseThrow(this.getExceptionSupplier("未找到数据, id=" + id, null));
    }

    @Override
    public Optional<UserThirdParty> getByUserId(Long userId, ThirdPartyType thirdPartyType) {
        return userThirdPartyDAO.findByUserIdAndThirdPartyType(userId, thirdPartyType).map(this::convertQBean);
    }

    @Override
    public UserThirdParty getByUserIdEnsure(Long userId, ThirdPartyType thirdPartyType) {
        return getByUserId(userId, thirdPartyType).orElseThrow(this.getExceptionSupplier("未找到数据, userId=" + userId, null));
    }

    @Override
    public Optional<UserThirdParty> getByThirdPartyAccount(String thirdPartyAccount, ThirdPartyType thirdPartyType) {
        return userThirdPartyDAO.findByThirdPartyAccountAndThirdPartyType(thirdPartyAccount, thirdPartyType).map(this::convertQBean);
    }

    @Override
    public List<UserThirdParty> findByIdCollection(Collection<Long> idCollection) {
        return convertStreamQBeanToList(userThirdPartyDAO.findByIdInOrderByIdDesc(idCollection).stream());
    }

    @Override
    public List<UserThirdParty> findByUserId(Long userId) {
        return convertStreamQBeanToList(userThirdPartyDAO.findByUserId(userId).stream());
    }

    @Override
    @Transactional
    public UserThirdParty save(UserThirdPartyCreator creator) throws UserLoginException {
        UserThirdPartyPO userThirdPartyPO = new UserThirdPartyPO();

        QBeanCreatorHelper.copyCreatorField(userThirdPartyPO, creator);

        return convertQBean(userThirdPartyDAO.save(userThirdPartyPO));
    }

    @Override
    @Transactional
    public UserThirdParty update(UserThirdPartyUpdater updater) throws UserThirdPartyException {
        UserThirdPartyPO userThirdPartyPO = getEntityWithNullCheckForUpdate(updater.getUpdateId(), userThirdPartyDAO);

        QBeanUpdaterHelper.copyUpdaterField(userThirdPartyPO, updater);

        return convertQBean(userThirdPartyPO);
    }

    @Override
    public QResponse<UserThirdParty> findAll(QRequest request, QPage requestPage) {
        return convertQResponse(findAllInternal(request, requestPage));
    }

    private Page<UserThirdPartyPO> findAllInternal(QRequest request, QPage requestPage) {
        return userThirdPartyDAO.findAll(convertSpecification(request), convertPageable(requestPage));
    }

    @Override
    public void deleteById(Long id) throws UserLoginException {
        UserThirdPartyPO userThirdPartyPO = getEntityWithNullCheckForUpdate(id, userThirdPartyDAO);
        userThirdPartyPO.setDeletedTime(System.currentTimeMillis());
    }

    @Override
    @Transactional
    public void bindThirdPartyWithLogin(UserThirdPartyCreator userThirdPartyCreator, LoginCheckType loginCheckType) {
        // 事务内 添加 三方关联
        UserThirdParty userThirdParty = save(userThirdPartyCreator);

        // 事务内 添加 登录信息
        userLoginService.save(UserLoginCreator
                .builder()
                .withUserId(userThirdParty.getUserId())
                .withLoginName(userThirdParty.getThirdPartyAccount())
                .withLoginNameType(LoginNameType.THIRD_PARTY)
                .withLoginCheckType(loginCheckType)
                .withLoginCheckId(userThirdParty.getId())
                .build());
    }

    @Override
    @Transactional
    public UserThirdParty bindThirdPartyWithLogin(Long sysUserId, UserThirdPartyCreator userThirdPartyCreator, LoginCheckType loginCheckType) {
        // 事务内 添加 三方关联
        UserThirdPartyPO userThirdPartyPO = new UserThirdPartyPO();
        QBeanCreatorHelper.copyCreatorField(userThirdPartyPO, userThirdPartyCreator);
        userThirdPartyPO.setUserId(sysUserId);
        userThirdPartyDAO.save(userThirdPartyPO);

        // 事务内 添加 登录信息
        userLoginService.save(UserLoginCreator
                .builder()
                .withUserId(userThirdPartyPO.getUserId())
                .withLoginName(userThirdPartyPO.getThirdPartyAccount())
                .withLoginNameType(LoginNameType.THIRD_PARTY)
                .withLoginCheckType(loginCheckType)
                .withLoginCheckId(userThirdPartyPO.getId())
                .build());

        return convertQBean(userThirdPartyPO);
    }

    @Override
    protected Supplier<? extends RuntimeException> getExceptionSupplier(String message,
                                                                        Throwable cause) {
        return () -> new UserLoginException(message, cause);
    }

}
